//wifi
#ifdef ARDUINO_ARCH_ESP32
  #include <WiFi.h>
#elif defined(ARDUINO_ARCH_ESP8266)
  #include <ESP8266WiFi.h>
#endif
//mqtt
#include <PubSubClient.h>

//wifi参数
char* wifiSsid = "";
char* wifiPassword = "";
char* wifiHostname = "";
//mqtt参数
char* mqttServer = "";
int mqttPort = 0;
char* mqttUsername = "";
char* mqttPassword = "";
String mqttClientId = "esp-mqtt-client-" + String(random(1000, 9999), DEC);
//mqtt在线topic
char* mqttOnlineTopic = "";
//mqtt订阅topic
String* mqttSubTopics;
int mqttSubTopicsNum = 0;

//mqtt是否连接着
bool isMqttConn = 0;

//定义mqtt client类
WiFiClient espClient;
PubSubClient client(espClient);

//打印日志
void logWifi(){
  // WiFi连接成功后将通过串口监视器输出连接成功信息
  // WiFi名称
  Serial.print("[MyWifiMqtt] Connected to ");
  Serial.println(WiFi.SSID());
  // IP
  Serial.print("[MyWifiMqtt] IP address: ");
  Serial.println(WiFi.localIP());
}

//初始化连接wifi
void initWifi(char* ssid, char* password){
  //连接网络
  WiFi.begin(ssid, password);
  //打印日志
  Serial.print("[MyWifiMqtt] connecting WiFi...");
  //等待网络连接成功
  while (WiFi.status() != WL_CONNECTED){
    delay(500);
    Serial.print(".");
  }
  //打印日志
  Serial.println("");
  Serial.print("[MyWifiMqtt] ESP Connected to ");
  Serial.println(WiFi.SSID());              // WiFi名称
  //打印地址
  Serial.print("[MyWifiMqtt] IP address: ");
  Serial.println(WiFi.localIP()); //打印模块IP
}

//初始化连接wifi-可以设置hostname
void initWifi(char* ssid, char* password, char* hostname){
  initWifi(ssid, password);
  //设置主机名
  WiFi.setHostname(hostname);
  //打印主机名
  Serial.print("[MyWifiMqtt] HostName: ");
  Serial.println(WiFi.getHostname());
}

//连接次数---超时断开并要求重新配置
int mqttErrorCount = 0;
//连上mqtt的操作
void mqttConnect(){
  //连接mqtt
  //boolean connect (clientID, willTopic, willQoS, willRetain, willMessage)
  //打印
  Serial.print("[MyWifiMqtt] clientId is: ");
  Serial.println(mqttClientId);
  bool isConnected = 0;
  //判断
  if(mqttUsername=="" && mqttPassword==""){
    isConnected = client.connect(mqttClientId.c_str(), mqttOnlineTopic, 0, true, "offline");
  }else{
    isConnected = client.connect(mqttClientId.c_str(), mqttUsername, mqttPassword, mqttOnlineTopic, 0, true, "offline");
  }
  //连接成功操作
  if(isConnected){
    //打印
    Serial.println("[MyWifiMqtt] Connected to MQTT server");
    //设置连接成功
    isMqttConn = 1;
    //订阅内容
    for(int i=0; i<  mqttSubTopicsNum; i++){
      Serial.print("[MyWifiMqtt] subscribe topic: ");
      Serial.println(mqttSubTopics[i]);
      client.subscribe(mqttSubTopics[i].c_str());
    }
    //发布复活消息
    client.publish(mqttOnlineTopic, "online");
  } else {
    mqttErrorCount++;
    //如果计数错误太多，直接删除配置重启
    if(mqttErrorCount == 50){
      if(WiFi.isConnected()){
        Serial.println("[MyWifiMqtt] 配置的mqtt无效，无法连接mqtt，删除所有内容重新进行设置！");
        //如果此时wifi连接着，说明为mqtt配置失败，重新启动
        ESP.restart();
      }else{
        //如果此时无法连接网络，说明网络已经断开，需要重新配网连接，但若是超时，亦能重新启动并按照旧密码连接！
        Serial.println("[MyWifiMqtt] wifi disconncted, please reconnect it!");
        initWifi("cyqand", "123cyq456");
      }
    }
    //打印错误码
    Serial.print("[MyWifiMqtt] Failed to connect to MQTT server, error count:");
    Serial.print(mqttErrorCount);
    Serial.print(", rc:");
    Serial.println(client.state());
    //等待1秒后重试
    delay(1000);
  }
}

//mqtt循环
void mqttLoop(){
  if (!client.connected()) {
    isMqttConn = 0;
    Serial.println("[MyWifiMqtt] Reconnecting to MQTT server...");
    mqttConnect();
  }else{
    isMqttConn = 1;
    mqttErrorCount = 0;
  }
  client.loop();
}

//以下为可以配置接口

//可以单独设置的参数:mqttCilentId、hostname、username、password
void setWifiHostname(char* hostname){
  wifiHostname = hostname;
}

void setMqttClientId(char* clientId){
  mqttClientId = clientId;
}

void setMqttUser(char* username, char* password){
  mqttUsername = username;
  mqttPassword = password;
}

//初始化wifi和mqtt
void initWifiMqtt(char* ssid, char* password, char* server, int port, char* onlineTopic, String subTopics[], int topicNum, void (*callback)(char *, byte *, unsigned int)){
  //设置连接基本参数
  wifiSsid = ssid;
  wifiPassword = password;
  mqttServer = server;
  mqttPort = port;
  mqttOnlineTopic = onlineTopic;
  mqttSubTopics = subTopics;
  mqttSubTopicsNum = topicNum;
  //连接wifi
  if(wifiHostname == ""){
    initWifi(wifiSsid, wifiPassword);
  }else{
    initWifi(wifiSsid, wifiPassword, wifiHostname);
  }
  //初始化mqtt
    //设置客户端
  client.setServer(mqttServer, mqttPort);
  client.setCallback(callback);
  while (!client.connected()) {
    Serial.println("[MyWifiMqtt] Connecting to MQTT server...");
    mqttConnect();
  }
}

//获取当前mqtt连接状态
bool mqttState(){
  return isMqttConn;
}

//获取wifi状态
bool wifiState(){
  return WiFi.isConnected();
}